/**
  ******************************************************************************
  * @file    usart.c
  * @brief   This file provides code for the configuration
  *          of the USART instances.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
/*! --------------------------------------------------------------------------*/
/*! Private variable definition */
#define USE_FREERTOS    1

#if USE_FREERTOS
#include "FreeRTOS.h"
#include "queue.h"
#include "portmacro.h"
#include "cmsis_os2.h"
#include "cmsis_os.h"
extern uint8_t isFreeRTOSSysOn;
extern osMessageQueueId_t usartRxMsgQueueHandle;
extern osMutexId_t usartMutexHandle;;
#endif

static uint8_t Uart1RxBuff[UART1_BUFF_SIZE+1] = {0};
static uint8_t isLogEnable = 1;                        /*! Log enable switch */
/*! --------------------------------------------------------------------------*/
/*! Public variable definition */
USART_RECEIVETYPE Uart1Rx;
USART_RECEIVETYPE Uart1Rx = { .RxBuff = Uart1RxBuff };
static char printf_buf[300];
/* USER CODE END 0 */

UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;
DMA_HandleTypeDef hdma_usart1_tx;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */

  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 DMA Init */
    /* USART1_RX Init */
    hdma_usart1_rx.Instance = DMA2_Stream2;
    hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_rx.Init.Mode = DMA_NORMAL;
    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA2_Stream7;
    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 7, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */

  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */

  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 DMA DeInit */
    HAL_DMA_DeInit(uartHandle->hdmarx);
    HAL_DMA_DeInit(uartHandle->hdmatx);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */

  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/*! -------------------------------------------------------------------------- */
/*! Public function definition */
/*  uart1 */
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void USART1_Init(uint32_t band,uint32_t parity)
{
  static uint32_t lastband;
  static uint8_t lastparity;

  if(lastband == band && lastparity == parity)
  {
    return;
  }
  lastband = band;
  lastparity = parity;

  switch(parity)
  {
    case 0:
        parity = UART_PARITY_NONE;
        break;
    case 1:
        parity = UART_PARITY_EVEN;
        break;
    case 2:
        parity = UART_PARITY_ODD;
        break;
    default:
        parity = UART_PARITY_NONE;
        break;
  }
  
  huart1.Instance = USART1;
  huart1.Init.BaudRate = band;
  if(parity == UART_PARITY_NONE)
  {
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
  }
  else
  {
    huart1.Init.WordLength = UART_WORDLENGTH_9B;
  }
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = parity;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE); 
  __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_TC); 
  HAL_UART_Receive_DMA(&huart1, Uart1Rx.RxBuff, UART1_BUFF_SIZE); 
  __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void USART1_ReceiveIDLE(void)  
{ 
  #if USE_FREERTOS
    uint32_t temp;  
    if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))  
    {
        __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE); 
        HAL_UART_DMAStop(&huart1);  
        temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
        Uart1Rx.RxLen =  UART1_BUFF_SIZE - temp;
        Uart1Rx.RxFlag = 1;  
        
        if( isFreeRTOSSysOn ){
            osMessageQueuePut(usartRxMsgQueueHandle,&Uart1Rx,0,0);
            Uart1Rx.RxFlag = 0;  
        }
        
        HAL_UART_Receive_DMA(&huart1,Uart1Rx.RxBuff,UART1_BUFF_SIZE);
    }
  #else
    uint32_t temp;  
    if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))  
    {
        __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE); 
        HAL_UART_DMAStop(&huart1);  
        temp = __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
        Uart1Rx.RxLen =  UART1_BUFF_SIZE - temp;   
        Uart1Rx.RxFlag = 1;  
        HAL_UART_Receive_DMA(&huart1,Uart1Rx.RxBuff,UART1_BUFF_SIZE);
    }
  #endif
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void UART_SendByte(UART_HandleTypeDef Huart,uint8_t data)
{
    #if USE_FREERTOS
    osMutexWait(usartMutexHandle,osWaitForever);
    #endif
    
    if(HAL_UART_Transmit(&Huart, &data, 1, 10)!= HAL_OK){
        Error_Handler();
    }
    
    #if USE_FREERTOS
    osMutexRelease(usartMutexHandle);
    #endif
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void UART_SendData(UART_HandleTypeDef Huart,uint8_t *buff,uint16_t size)
{
    #if USE_FREERTOS
    osMutexWait(usartMutexHandle,osWaitForever);
    #endif
    
    if(HAL_UART_Transmit(&Huart, buff, size,1000)!= HAL_OK){
        Error_Handler();
    }
    
    #if USE_FREERTOS
    osMutexRelease(usartMutexHandle);
    #endif
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void UART_SendString(UART_HandleTypeDef Huart,char *str)
{
    __IO uint32_t strlength;
    strlength = strlen(str);
    
    #if USE_FREERTOS
    osMutexWait(usartMutexHandle,osWaitForever);
    #endif
    
    if(HAL_UART_Transmit(&Huart, (uint8_t*)str, strlength,2000)!= HAL_OK){
        Error_Handler();
    }
    
    #if USE_FREERTOS
    osMutexRelease(usartMutexHandle);
    #endif
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
bool UART_ReadRxBuffWithTimeout(USART_RECEIVETYPE uartRx, uint16_t timeout_ms)
{
    while(!uartRx.RxFlag && (timeout_ms-- > 0) ){ HAL_Delay(1); }
    if(uartRx.RxFlag){
        uartRx.RxFlag = 0;
        uartRx.RxBuff[uartRx.RxLen] = 0;
        return true;
    }
    else{ return false; }
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void msgPrintf(char *fmt, ...)
{
    va_list va_args;
    if(isLogEnable){    
        va_start(va_args, fmt);// Start the varargs processing.
        vsnprintf((char *)printf_buf, sizeof(printf_buf), fmt, va_args);
        va_end(va_args);// End the varargs processing.
        UART_SendString(DEBUG_HUART,printf_buf);//Uart1 for Debuf_Printf
    }
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void DEBUG_PrintfHEX(uint8_t *pdata, uint16_t length)
{
  uint16_t i;
  if(pdata == 0 || length == 0)
      return;
  for(i=0;i<length;i++){
    msgPrintf("%02x ",*(pdata+i));
  }
  msgPrintf("\r\n");
}
/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
void DEBUG_PrintfASCII(uint8_t *pdata, uint16_t length)
{
  uint16_t i;
  if(pdata == 0 || length == 0)
      return;
  for(i=0;i<length;i++){
    msgPrintf("%c",*(pdata+i));
  }
  msgPrintf("\r\n");
}
/* USER CODE END 1 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
